package com.oig.sys.base.service.impl;

import cn.hutool.core.util.StrUtil;
import com.oig.common.constants.CommonEnum;
import com.oig.common.exception.BadRequestException;
import com.oig.common.module.SysRequest;
import com.oig.sys.base.dao.ITbHarborDao;
import com.oig.sys.base.dto.HarborDto;
import com.oig.sys.base.entity.TbHarbor;
import com.oig.sys.base.service.ITbHarborService;
import com.oig.sys.base.vo.HarborVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.List;

/**
 * @author wuxl
 */
@Service
public class TbHarborServiceImpl implements ITbHarborService {

	private final ITbHarborDao tbHarborDao;

	@Autowired
	public TbHarborServiceImpl(ITbHarborDao tbHarborDao){
		 this.tbHarborDao = tbHarborDao;
	}

	@Transactional
	@Override
	public HarborVo addTbHarbor(HarborDto harborDto) {
		TbHarbor harbor = this.tbHarborDao.getByCode(harborDto.getCode()) ;
		if (harbor!=null){
			throw new BadRequestException("代码重复");
		}
		harbor = this.tbHarborDao.getByName(harborDto.getName());
		if (harbor!=null){
			throw new BadRequestException("名称重复");
		}
		harbor = new TbHarbor();
		BeanUtils.copyProperties(harborDto, harbor);
		harbor.setStatus(CommonEnum.CommonStatusEnum.OK.getCode());
		this.tbHarborDao.save(harbor) ;

		return this.buildVo(harbor);
	}

	private HarborVo buildVo(TbHarbor harbor){
		HarborVo harborVo = new HarborVo();
		BeanUtils.copyProperties(harbor, harborVo);
		return harborVo;
	}

	@Transactional
	@Override
	public HarborVo updateTbHarbor(HarborDto harborDto) {
		TbHarbor harbor = this.tbHarborDao.getTbHarborById(harborDto.getId()) ;
		if (harbor==null){
			throw new BadRequestException("口岸不存在");
		}
		TbHarbor harbor1 = this.tbHarborDao.getByCodeAndIdExists(harborDto.getCode(),harbor.getId());
		if (harbor1!=null){
			throw new BadRequestException("代码重复");
		}
		if (!harbor.getName().equals(harborDto.getName())){
			harbor1 = this.tbHarborDao.getByName(harborDto.getName());
			if (harbor1!=null){
				throw new BadRequestException("名称重复");
			}
		}
		BeanUtils.copyProperties(harborDto, harbor, "id","status");
		this.tbHarborDao.save(harbor) ;

		return this.buildVo(harbor);
	}

	@Transactional
	@Override
	public HarborVo cancelTbHarbor(Integer id) {
		TbHarbor harbor = this.tbHarborDao.getTbHarborById(id) ;
		if (harbor==null){
			throw new BadRequestException("口岸不存在");
		}
		if (CommonEnum.CommonStatusEnum.DEL.getCode().equals(harbor.getStatus())){
			throw new BadRequestException("口岸已删除");
		}
		harbor.setStatus(CommonEnum.CommonStatusEnum.DEL.getCode());
		this.tbHarborDao.save(harbor) ;
		return this.buildVo(harbor);
	}

	@Override
	public List<HarborVo> findHarbor(SysRequest<HarborDto> harborRequest) {
		Pageable pageable = harborRequest.pageable();
		Page<TbHarbor> page ;
		if (harborRequest.getParamDto()!=null){
			Specification<TbHarbor> specification = new Specification<TbHarbor>() {
				@Override
				@Nullable
				public Predicate toPredicate(@NonNull Root<TbHarbor> root, @NonNull CriteriaQuery<?> criteriaQuery, @NonNull CriteriaBuilder criteriaBuilder) {
					List<Predicate> predicateList = new ArrayList<>();
					if (StrUtil.isNotBlank(harborRequest.getParamDto().getCode())) {
						Path<String> codePath = root.get("code");
						predicateList.add(criteriaBuilder.equal(codePath, harborRequest.getParamDto().getCode()));
					}
					if (StrUtil.isNotBlank(harborRequest.getParamDto().getName())) {
						Path<String> namePath = root.get("name");
						predicateList.add(criteriaBuilder.like(namePath, "%" + harborRequest.getParamDto().getName() + "%"));
					}
					if (StrUtil.isNotBlank(harborRequest.getParamDto().getCountryCode())) {
						Path<String> countryCodePath = root.get("countryCode");
						predicateList.add(criteriaBuilder.equal(countryCodePath, harborRequest.getParamDto().getCountryCode()));
					}
					if (StrUtil.isNotBlank(harborRequest.getParamDto().getCityCode())) {
						Path<String> cityCodePath = root.get("cityCode");
						predicateList.add(criteriaBuilder.equal(cityCodePath, harborRequest.getParamDto().getCityCode()));
					}
					if (harborRequest.getParamDto().getCustomsId()!=null) {
						Path<Integer> customsCodePath = root.get("customsId");
						predicateList.add(criteriaBuilder.equal(customsCodePath, harborRequest.getParamDto().getCustomsId()));
					}
					Path<String> statusPath = root.get("status");
					if (StrUtil.isNotBlank(harborRequest.getParamDto().getStatus())) {
						predicateList.add(criteriaBuilder.equal(statusPath, harborRequest.getParamDto().getStatus()));
					} else {
						predicateList.add(criteriaBuilder.equal(statusPath, CommonEnum.CommonStatusEnum.OK.getCode()));
					}
					criteriaQuery.where(predicateList.toArray(new Predicate[0]));
					return criteriaQuery.getRestriction();
				}
			};
			page = this.tbHarborDao.findAll(specification,pageable);
		} else {
			page = this.tbHarborDao.findAll(pageable);
		}
		List<HarborVo> harborVoList = new ArrayList<>();
		for (TbHarbor harbor : page.getContent()){
			harborVoList.add(this.buildVo(harbor));
		}
		return harborVoList;
	}


	@Override
	public HarborVo getByCode(String code) {
		TbHarbor harbor= this.tbHarborDao.getByCode(code);
		if (harbor==null)
			return null;
		return this.buildVo(harbor);
	}

	@Override
	public HarborVo getByName(String name) {
		TbHarbor harbor= this.tbHarborDao.getByName(name);
		if (harbor==null)
			return null;
		return this.buildVo(harbor);
	}

	@Override
	public HarborVo getByOldCode(String oldCode) {
		TbHarbor harbor= this.tbHarborDao.getByOldCode(oldCode);
		if (harbor==null)
			return null;
		return this.buildVo(harbor);
	}

}
